home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
NNTPSERV.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
20KB
|
946 lines
/*
*
* NNTP Server - See RFC977
* Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
* Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
* DB3FL 920121: splitted into several files
*
*/
#include <dos.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <io.h>
#include "global.h"
#include "config.h"
#ifdef NNTP
#include "nntp.h"
#include "socket.h"
#include "files.h"
#include "ftp.h"
#ifdef LZW
#include "lzw.h"
#endif
#include "server.h"
#undef CONTROL /* (not implemented yet) */
#undef XINFO /* (not really needed) */
#ifdef LZW
int LzwActive = 1;
#endif
#ifdef NNTPENH
int fullauto = 1;
#endif
#ifdef POST_ENBL
#define IHAVE_CMD 0
#define POST_CMD 1
int postingok = 1;
#endif
unsigned short Nntpmaxcli = 3;
static unsigned short Nntpsessions = 0;
char artmsg[] = " Article retrieved - ";
static char debug[] = "100 DEBUG %s\n";
#if (defined(POST_ENBL) && defined(XHEADER))
static char help[] = "100-ARTICLE BODY GROUP HEAD HELP IHAVE LAST LIST\n"
"100 NEWNEWS NEXT POST QUIT STAT XHDR XINFO\n";
#elif (defined(POST_ENBL))
static char help[] = "100-ARTICLE BODY GROUP HEAD HELP IHAVE LAST\n"
"100 LIST NEWNEWS NEXT POST QUIT STAT XINFO\n";
#else
static char help[] = "100-ARTICLE BODY GROUP HEAD HELP IHAVE\n"
"100 LAST LIST NEWNEWS NEXT QUIT STAT XINFO\n";
#endif
static char noactive[] = "100 No active newsgroups\n";
#ifdef XINFO
static char xinfo[] = "100 %s no info available\n";
#endif
#ifdef POST_ENBL
static char nnversion[] = "20%c %s NNTP version %s ready at %s GMT\n";
#else
static char nnversion[] = "201 %s NNTP version %s ready at %s GMT\n";
#endif
static char slave[] = "202 SLAVE %s\n";
static char closing[] = "205 Closing\n";
static char listarticle[] = "211 %u %u %u %s\n";
static char listgrps[] = "215 Available newsgroups\n";
char retrieve[] = "220 %u%s%shead and body follow\n";
static char head[] = "221 %u%s%sHead\n";
#ifdef XHEADER
static char extrfoll[] = "221 %s fields follow\n";
#endif
static char body[] = "222 %u%s%sBody\n";
static char statistics[] = "223 %u%s%sStatistics\n";
static char sepcmd[] = "223 %u%s%srequest text separately\n";
static char newnews_t[] = "230 New news by message id follows\n";
static char transok[] = "235 Thanks\n";
#ifdef POST_ENBL
static char postok[] = "240 Article posted ok\n";
#endif
static char sendart[] = "335 Send article, end with .\n";
#ifdef POST_ENBL
static char sendpost[] = "340 Send article to be posted, end with .\n";
#endif
static char nogroup[] = "411 No such newsgroup\n";
static char noselect[] = "412 No newsgroup selected\n";
static char nonext[] = "421 No next article\n";
static char noprev[] = "422 No previous article\n";
char noart[] = "430 No such article\n";
static char notwanted[] = "435 Article not wanted - do not send it\n";
static char transnotok[] = "437 Article rejected - do not try again\n";
#ifdef POST_ENBL
static char noposting[] = "440 Posting not allowed\n";
static char postfailed[] = "441 Posting failed\n";
#endif
char badsyntax[] = "501 Syntax error\n";
static char error[] = "503 Command not performed\n";
static char lowmem[] = "503 System is overloaded\n";
char NEol[] = ".\n";
#ifdef CONTROL
static int near
docontrol(FILE *f,struct nntpserv *mp)
{
struct head *h;
if(f == NULLFILE)
return -1;
h = mxallocw(sizeof(struct head));
rewind(f);
h->subject = h->from = h->reply_to = h->id = NULLCHAR;
for(;;) {
if (fgets(mp->buf,LineLen,f) == NULL)
break;
if (check_blank(mp->buf))
break;
rip(mp->buf);
if (strncmp(mp->buf,Hdrs[SUBJECT],9) == 0)
h->subject = strxdup(mp->buf);
if (strncmp(mp->buf,Hdrs[FROM],6) == 0)
h->from = strxdup(mp->buf);
if (strnicmp(mp->buf,Hdrs[REPLYTO],10) == 0)
h->reply_to = strxdup(mp->buf);
if (strnicmp(mp->buf,Hdrs[MSGID],12) == 0)
h->id = strxdup(strchr(mp->buf,'<'));
}
if (h->subject != NULLCHAR)
if (strncmp(h->subject,"Subject: sendme ",16) == 0)
dosendme(h);
if (h->subject != NULLCHAR)
xfree(h->subject);
if (h->from != NULLCHAR)
xfree(h->from);
if (h->reply_to != NULLCHAR)
xfree(h->reply_to);
if (h->id != NULLCHAR)
xfree(h->id);
xfree(h);
return 0;
}
#endif
/* checks if newsgroup is selected
* returncode: -1 no group selected; 0 success */
static int near
check_grp(struct nntpserv *mp)
{
if(mp->path == NULLCHAR) {
usputs(mp->s,noselect);
return -1;
}
return 0;
}
static int near
set_pointer(struct nntpserv *mp)
{
char *cp;
if((cp = strpbrk(mp->buf,"0123456789")) != NULLCHAR) {
int cnt = atoi(cp);
if((cnt > mp->last) || ( cnt < mp->first)) {
usputs(mp->s,noart);
return -1;
}
mp->pointer = cnt;
}
return 0;
}
#ifdef POST_ENBL
static void near
_ihave_sub(struct nntpserv *mp,int command)
{
char *cp;
if((cp = strchr(mp->buf,'<')) == NULLCHAR) {
usputs(mp->s,badsyntax);
} else if(check_article(cp) == 1) {
usputs(mp->s,notwanted);
} else {
FILE *f;
int ret = -1;
usputs(mp->s,sendart);
if(mp->buf == NULLCHAR
|| *(mp->buf + 1) < ' '
|| (f = Tmpfile(0,1)) == NULLFILE)
return;
if(recv_file(f,mp->s) != -1) {
char *cp;
int foundmid = 0;
/* get id-number from article, not from IHAVE offer */
rewind(f);
while(fgets(mp->buf,LineLen,f) != NULL) {
rip(mp->buf);
if(strnicmp(mp->buf,Hdrs[MSGID],12) == 0) {
if((cp = strchr(mp->buf,'<')) != NULLCHAR) {
mp->id = strxdup(cp);
foundmid = 1;
break;
}
}
}
/* minimum header in article required !
Now check again, if same news exists in history */
if(foundmid == 1 && check_article(mp->id) == 0 && garbled(f) == 0) {
rewind(f);
ret = xfer_article2(f,mp);
} else if(foundmid) {
xfree(mp->id);
}
}
Fclose(f);
if(command == POST_CMD) {
usputs(mp->s,ret ? postfailed : postok);
} else {
usputs(mp->s,ret ? transnotok : transok);
}
}
return;
}
#endif
/*-------------------------- NNTP server subcmds ---------------------------*/
static void near
article_command(struct nntpserv *mp)
{
if(*mp->buf == '<') {
doarticle(mp,1,NULLCHAR);
} else if(check_grp(mp) == 0) {
FILE *fp;
if(!check_blank(mp->buf)) {
if(set_pointer(mp)) {
return;
}
}
if((fp = open_message(mp)) != NULLFILE) {
art_ret(mp,1);
sendfile(fp,mp->s,ASCII_TYPE,0x80);
usputs(mp->s,NEol);
}
}
return;
}
static void near
body_command(struct nntpserv *mp)
{
if(check_grp(mp) == 0) {
if(set_pointer(mp) == 0) {
if(get_id(mp) == 1) {
FILE *fp;
usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
if ((fp = open_message(mp)) != NULLFILE) {
mp->hold_i = 0;
while(fgets(mp->buf,LineLen,fp) != NULL) {
if(mp->hold_i)
usputs(mp->s,mp->buf);
if(check_blank(mp->buf))
mp->hold_i = 1;
}
Fclose(fp);
}
usputs(mp->s,NEol);
}
}
}
return;
}
static void near
debug_command(struct nntpserv *mp)
{
mp->states ^= N_DEBUG;
usprintf(mp->s,debug,(mp->states & N_DEBUG) ? "ON" : "OFF");
return;
}
/* Change current newsgroup */
static void near
group_command(struct nntpserv *mp)
{
FILE *f;
char line[LineLen];
switch(get_path(mp)) {
case 0:
usputs(mp->s,nogroup);
return;
default:
if((f = Fopen(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
char *cp;
while(fgets(line,LineLen,f) != NULL) {
if(strcspn(line," ") != strlen(mp->buf))
continue;
if(strnicmp(mp->buf,line,strlen(mp->buf))==0) {
cp = strchr(line,' ');
mp->last = atoi(cp);
mp->first = atoi(strchr(++cp,' '));
mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
usprintf(mp->s,
listarticle,
mp->last - mp->first + 1,
mp->first,
mp->last,
mp->buf);
Fclose(f);
return;
}
}
Fclose(f);
}
case -1:
usputs(mp->s,error);
return;
}
}
static void near
head_command(struct nntpserv *mp)
{
if(check_grp(mp) == 0) {
if(set_pointer(mp) == 0) {
if(get_id(mp) == 1) {
FILE *fp;
usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
if((fp = open_message(mp)) != NULLFILE) {
while(fgets(mp->buf,LineLen,fp) != NULL) {
if(check_blank(mp->buf))
break;
usputs(mp->s,mp->buf);
}
Fclose(fp);
}
usputs(mp->s,NEol);
}
}
}
return;
}
static void near
help_command(struct nntpserv *mp)
{
FILE *fp;
usprintf(mp->s,"100-%s - help follows\n",Hostname);
if((fp = Fopen(Nhelp,READ_TEXT,0,0)) != NULLFILE ) {
sendfile(fp,mp->s,ASCII_TYPE,0x80);
} else {
usputs(mp->s,help);
}
usputs(mp->s,NEol);
return;
}
#ifdef POST_ENBL
static void near
ihave_command(struct nntpserv *mp)
{
_ihave_sub(mp,IHAVE_CMD);
}
#else
static void near
ihave_command(struct nntpserv *mp)
{
char *cp;
if((cp = strchr(mp->buf,'<')) == NULLCHAR) {
usputs(mp->s,badsyntax);
} else if(check_article(cp) == 1) {
usputs(mp->s,notwanted);
} else {
FILE *f;
int ret = -1;
usputs(mp->s,sendart);
if(mp->buf == NULLCHAR
|| *(mp->buf + 1) < ' '
|| (f = Tmpfile(0,1)) == NULLFILE)
return;
if(recv_file(f,mp->s) != -1) {
char *cp;
int foundmid = 0;
/* get id-number from article, not from IHAVE offer */
rewind(f);
while(fgets(mp->buf,LineLen,f) != NULL) {
rip(mp->buf);
if(strnicmp(mp->buf,msgid,12) == 0) {
if((cp = strchr(mp->buf,'<')) != NULLCHAR) {
mp->id = strxdup(cp);
foundmid = 1;
break;
}
}
}
/* minimum header in article required !
Now check again, if same news exists in history */
if(foundmid == 1 && check_article(mp->id) == 0 && garbled(f) == 0) {
rewind(f);
ret = xfer_article2(f,mp);
} else if(foundmid) {
xfree(mp->id);
}
}
Fclose(f);
usputs(mp->s,ret ? transnotok : transok);
}
return;
}
#endif
static void near
last_command(struct nntpserv *mp)
{
if(check_grp(mp) == 0) {
for (;;) {
if (mp->pointer == 0) {
usputs(mp->s,noprev);
return;
}
if (--mp->pointer < mp->first) {
mp->pointer++;
usputs(mp->s,noprev);
return;
}
sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
if(access(mp->buf,0) == 0) {
if(get_id(mp) == 1) {
usprintf(mp->s,sepcmd,mp->pointer,mp->buf,artmsg);
}
return;
}
}
}
return;
}
static void near
list_command(struct nntpserv *mp)
{
FILE *fp;
if((fp = Fopen(Active,READ_TEXT,0,0)) != NULLFILE) {
usputs(mp->s,listgrps);
sendfile(fp,mp->s,ASCII_TYPE,0x80);
usputs(mp->s,NEol);
} else {
usputs(mp->s,noactive);
}
return;
}
static void near
newnews_command(struct nntpserv *mp)
{
FILE *f;
if((f = Tmpfile(mp->s,1)) != NULLFILE) {
int ret = newnews(mp,f);
switch(ret) {
case -1: /* error in "newnews" routine */
ret = 0;
usputs(mp->s,badsyntax);
break;
default:
usputs(mp->s,newnews_t);
if(ret) {
ret = (int)sendfile(f,mp->s,ASCII_TYPE,0);
}
if(ret != -1) {
usputs(mp->s,NEol);
}
break;
}
Fclose(f);
}
return;
}
static void near
next_command(struct nntpserv *mp)
{
if(check_grp(mp) == 0) {
for (;;) {
if(mp->pointer == 0 ) {
usputs(mp->s,nonext);
return;
}
if(++mp->pointer > mp->last) {
mp->pointer--;
usputs(mp->s,nonext);
return;
}
sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
if(access(mp->buf,0) == 0) {
if(get_id(mp) == 1) {
usprintf(mp->s,sepcmd,mp->pointer,mp->buf,artmsg);
}
return;
}
}
}
return;
}
#ifdef POST_ENBL
static void near
post_command(struct nntpserv *mp)
{
if(postingok) {
usputs(mp->s,sendpost);
_ihave_sub(mp,POST_CMD);
} else {
usputs(mp->s,noposting);
}
return;
}
#endif
static void near
quit_command(struct nntpserv *mp)
{
usputs(mp->s,closing);
mp->states = CLOSED;
return;
}
static void near
slave_command(struct nntpserv *mp)
{
mp->states ^= N_SLAVE;
usprintf(mp->s,slave,(mp->states & N_SLAVE) ? "ON" : "OFF");
return;
}
static void near
stat_command(struct nntpserv *mp)
{
if(check_grp(mp) == 0) {
if(set_pointer(mp) == 0) {
if(get_id(mp) == 1) {
usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
}
}
}
return;
}
#ifdef XHEADER
static void near
xhdr_command(struct nntpserv *mp)
{
FILE *fp;
char c = 0, fname[MAXPATH + 10], t[20];
int first = 0, last = 0, t_len;
/* It must be a range of articles, which means that we need
* to be in a newsgroup already. */
if(check_grp(mp) == -1) {
return;
}
if(mp->pointer == 0) {
usputs(mp->s,noart);
return;
}
/* Handle message-id requests */
if(strchr(mp->buf,'<') != NULLCHAR) {
doarticle(mp,1,NULLCHAR);
return;
}
if(sscanf(mp->buf,"%18s %d%c%d",t,&first,&c,&last) < 2) {
usputs(mp->s,badsyntax);
return;
}
t_len = strlen(t);
if(first < mp->first) {
first = mp->first;
}
if(!c) {
last = first;
}
if(!last || last > mp->last) {
last = mp->last;
}
if(first > last) {
first = last;
}
usprintf(mp->s,extrfoll,strupr(t));
do {
mp->pointer = first;
sprintf(fname,"%s/%u",mp->path,mp->pointer);
if((fp = Fopen(fname,READ_TEXT,0,0)) != NULLFILE) {
while(fgets(mp->buf,LineLen,fp) != NULL) {
if(*mp->buf == '\n' || *mp->buf == '\0') {
/* usprintf(mp->s,"%d (none)\n",mp->pointer); */
break;
}
if(strnicmp(t,mp->buf,t_len) == 0) {
char *cp = strchr(mp->buf,' ');
usprintf(mp->s,"%d %s",mp->pointer,cp + 1);
break;
}
}
Fclose(fp);
}
} while(first++ < last);
usputs(mp->s,NEol);
}
#endif
#ifdef XINFO
static void near
xinfo_command(struct nntpserv *mp)
{
FILE *fp;
if((fp = Fopen(NInfo,READ_TEXT,0,0)) != NULLFILE ) {
usprintf(mp->s,"100-%s - info follows\n",Hostname);
sendfile(fp,mp->s,ASCII_TYPE,0x80);
} else {
usprintf(mp->s,xinfo,Hostname);
}
usputs(mp->s,NEol);
return;
}
#endif
#ifdef LZW
static void near
xlzw_command(struct nntpserv *mp)
{
if(LzwActive) {
int lzwbits = 99;
int lzwmode = -1;
sscanf(mp->buf,"%d %d",&lzwbits,&lzwmode);
if(lzwbits > lzwmode && 9 < lzwbits && lzwbits < 17
&& (lzwmode == 0 || lzwmode == 1)) {
usputs(mp->s,transok);
lzwinit(mp->s,lzwbits,lzwmode);
} else {
usputs(mp->s,error);
}
}
}
#endif
void
nntpserv(int s,void *unused,void *p)
{
/* Command table */
static struct cmdtable {
char *name;
void near (*func) __ARGS((struct nntpserv *mp));
int states;
} cmdtable[] = {
{"ARTICLE", article_command, 0},
{"BODY", body_command, 0},
{"DEBUG", debug_command, 0},
{"GROUP", group_command, 0},
{"HEAD", head_command, 0},
{"HELP", help_command, 0},
{"IHAVE", ihave_command, 0},
{"LAST", last_command, 0},
{"LIST", list_command, 0},
{"NEWNEWS", newnews_command, 0},
{"NEXT", next_command, 0},
#ifdef POST_ENBL
{"POST", post_command, 0},
#endif
{"QUIT", quit_command, 0},
{"SLAVE", slave_command, 0},
{"STAT", stat_command, 0},
#ifdef XHEADER
{"XHDR", xhdr_command, 0},
#endif
#ifdef XINFO
{"XINFO", xinfo_command, 0},
#endif
#ifdef LZW
{"XLZW", xlzw_command, 0},
#endif
{0, 0, 0},
};
struct cmdtable *cmdp;
int arglen;
char *cp, *cp1;
struct nntpserv *mp;
sockowner(s,Curproc); /* We own it now */
sockmode(s,SOCK_ASCII);
if(!Filecheck)
if(check_system()) {
usputs(s,"503 Fatal error in structure\n");
close_s(s);
return;
}
cp = ctime(&currtime);
cp[24] = '\0';
#ifdef POST_ENBL
usprintf(s,nnversion,postingok ? '0' : '1',Hostname,Version,cp);
#else
usprintf(s,nnversion,Hostname,Version,cp);
#endif
if(++Nntpsessions > Nntpmaxcli) {
usputs(s,lowmem);
close_s(s);
return;
}
mp = mxallocw(sizeof(struct nntpserv));
mp->buf = mxallocw(LineLen);
mp->s = s;
log(mp->s,9983,"NNTP open");
for( ; ;) {
loop:
if(mp->states == CLOSED) {
break;
}
if(recvline(mp->s,mp->buf,LineLen) <= 0) {
/* He closed on us */
break;
}
rip(mp->buf);
arglen = 0;
cp = mp->buf;
while(isspace(*cp)) {
cp++;
}
cp1 = cp;
while(*cp1 != '\0' && !isspace(*cp1)) {
cp1++;
arglen++;
}
if(arglen) {
for(cmdp = cmdtable; cmdp->name; cmdp++) {
if(strnicmp(cmdp->name,cp,arglen) == 0) {
char *line, *cp2 = cp1;
while(*cp2 != '\0' && isspace(*cp2)) {
cp2++;
}
line = strxdup(cp2);
/* Translate entire buffer to lower case */
strlwr(line);
strcpy(mp->buf,line);
xfree(line);
pwait(NULL); /* TEST */
(*cmdp->func)(mp);
goto loop;
}
}
}
/* Can't be a legal command */
usputs(mp->s,error);
}
quit:
log(mp->s,9983,"NNTP close");
close_s(mp->s);
Nntpsessions--;
if(mp->path != NULLCHAR) {
xfree(mp->path);
}
if(mp->newnews != NULLCHAR) {
xfree(mp->newnews);
}
xfree(mp->buf);
xfree(mp);
}
/* ---------------------------- SMTP->NNTP-GATE --------------------------- */
int
nnGpost(FILE *data,char *from,struct list *le)
{
FILE *f;
struct nntpserv *mp;
int msgidfound = 0;
char buf[LineLen], *cp, *cp1;
if (!Filecheck)
if(check_system())
return -1;
if ((f = Tmpfile(0,1)) == NULLFILE)
return -1;
mp = mxallocw(sizeof(struct nntpserv));
/* build path */
cp = strxdup(from);
if((cp1 = strpbrk(cp,"@. ")) != NULLCHAR)
*cp1 = '\0';
cp1 = strxdup(cp);
if(strchr(cp1,'%') != NULLCHAR) {
char *cp2, *revpath = strxdup(cp1);
*cp1 = '\0';
while((cp2 = strrchr(revpath,'%')) != NULLCHAR) {
*cp2++ = '\0';
strcat(cp1,cp2);
strcat(cp1,"!");
}
strcat(cp1,revpath);
xfree(revpath);
}
fprintf(f,"%s%s\n",Hdrs[PATH],cp1);
xfree(cp1);
/* look for msg-id */
rewind(data);
while(fgets(buf,LineLen,data) != NULL) {
if(*buf == '\t' || *buf == ' ')
continue;
rip(buf);
if(*buf == '\0')
break;
if(htype(buf) == MSGID) {
msgidfound = 1;
break;
}
}
/* reorganize header */
rewind (data);
while(fgets(buf,LineLen,data) != NULL) {
if(*buf == '\t' || *buf == ' ')
continue;
rip(buf);
if(*buf == '\0')
break;
switch(htype(buf)) {
case FROM:
/* generating from line */
fprintf(f,"%s%s@%s",Hdrs[FROM],cp,Hostname);
if((cp1 = strpbrk(buf,"<(")) != NULLCHAR)
fprintf(f," %s",cp1);
/* generating newsgroups line */
if((cp1 = strpbrk(&le->val[1],"!@")) != NULLCHAR)
*cp1 = '\0';
fprintf(f,"\n%s%s\n",Hdrs[NEWSGROUPS],&le->val[1]); /* skip the bang */
continue;
case SUBJECT:
fprintf(f,"%s\n",strlen(buf) < 10 ? "Subject: (none)" : buf);
if(msgidfound == 0) {
sprintf(mp->buf,"<%ld@%s>",get_msgid(),Hostname);
fprintf(f,"%s%s\n",Hdrs[MSGID],mp->buf);
mp->id = strxdup(mp->buf);
}
fprintf(f,"Sender: NNTP@%s\n",Hostname);
continue;
case MSGID:
if(msgidfound == 1) {
fprintf(f,"%s\n",buf);
if((cp1 = strchr(buf,'<')) != NULLCHAR) {
sprintf(mp->buf,"%s",cp1);
mp->id = strxdup(cp1);
}
}
continue;
case TO:
case RECEIVED:
case SENDER:
case STATUS:
case NOHEADER:
continue;
}
fprintf(f,"%s\n",buf);
}
xfree(cp);
fputc('\n',f);
while(fgets(buf,LineLen,data) != NULL)
fputs(buf,f);
fflush(f);
rewind(f);
xfer_article2(f,mp);
Fclose(f);
xfree(mp);
return 0;
}
#endif /* NNTP */